package com.sandyz.virtualcam.utils

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.children
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.sandyz.virtualcam.hooks.IHook
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import java.lang.ref.WeakReference
import kotlin.coroutines.CoroutineContext

/**
 * Hook工具类
 * 
 * 主要功能：
 * 1. Activity生命周期管理
 * 2. 协程作用域管理
 * 3. 日志记录
 * 4. UI操作工具
 * 5. Hook初始化
 * 
 * 实现细节：
 * - 使用WeakReference管理Activity引用
 * - 支持多种Lifecycle实现
 * - 提供统一的日志接口
 * - 协程异常处理
 * 
 * @author sandyz987
 * @date 2023/11/18
 */
@SuppressLint("StaticFieldLeak")
object HookUtils {
    // 1. 全局变量
    var app: Context? = null  // 应用上下文

    // 2. Activity管理
    private val activityTop = mutableListOf<WeakReference<Activity>>()  // Activity栈

    /**
     * 2.1 获取所有活动的Activity
     * 清理已销毁的Activity引用
     * 
     * @return List<Activity> 活动的Activity列表
     */
    fun getActivities(): List<Activity> {
        val activities = mutableListOf<Activity>()
        val iterator = activityTop.iterator()
        while (iterator.hasNext()) {
            val activity = iterator.next().get()
            if (activity != null && !activity.isFinishing) {
                activities.add(activity)
            } else {
                iterator.remove()
            }
        }
        return activities
    }

    /**
     * 2.2 获取栈顶Activity
     * 
     * @return Activity? 栈顶Activity，如果栈为空则返回null
     */
    fun getTopActivity(): Activity? {
        val activities = getActivities()
        return if (activities.isEmpty()) {
            null
        } else {
            activities[0]
        }
    }

    /**
     * 2.3 获取Activity的Lifecycle
     * 支持多种Lifecycle实现，通过反射提高兼容性
     * 
     * @return Lifecycle? Activity的Lifecycle对象
     */
    fun getLifecycle(): Lifecycle? {
        val activity = getTopActivity()
        mutableListOf(
            "androidx.lifecycle.LifecycleOwner",
            "android.arch.lifecycle.LifecycleOwner",
            "android.support.v4.app.FragmentActivity",
            "android.support.v4.app.SupportActivity",
            "androidx.fragment.app.FragmentActivity",
            "androidx.appcompat.app.AppCompatActivity",
            "androidx.activity.ComponentActivity",
            "androidx.core.app.ComponentActivity",
        ).forEach {
            try {
                val clazz = try {
                    XposedHelpers.findClass(it, activity?.classLoader)
                } catch (t: Throwable) {
                    Class.forName(it)
                }
                val activityCast = clazz?.cast(activity)
                val function = clazz?.getDeclaredMethod("getLifecycle")
                function?.isAccessible = true
                val lifecycle = function?.invoke(activityCast) as? Lifecycle
                if (lifecycle != null) {
                    return lifecycle
                } else {
                    xLog("lifecycle is null")
                }
            } catch (t: Throwable) {
                xLog(t.toString())
            }
        }
        return null
    }

    // 3. 协程管理
    private val coroutineScopeMap = HashMap<Activity, CoroutineScope>()

    /**
     * 3.1 获取Activity的协程作用域
     * 自动管理协程生命周期
     * 
     * @return CoroutineScope 协程作用域
     */
    fun coroutineScope(): CoroutineScope = if (coroutineScopeMap[getTopActivity()] != null) {
        coroutineScopeMap[getTopActivity()]!!
    } else {
        MyCoroutineScope().also {
            xLog("activity: ${getTopActivity()}")
            xLog("lifecycle2: ${getLifecycle()}")
            val activity = getTopActivity()?: return@also
            val activityLifecycle = getLifecycle()?: return@also
            val lifecycleEventObserver = object :LifecycleEventObserver {
                override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                    if (event == Lifecycle.Event.ON_DESTROY) {
                        it.cancel()
                        activityLifecycle.removeObserver(this)
                        coroutineScopeMap.remove(activity)
                    }
                }
            }
            activityLifecycle.addObserver(lifecycleEventObserver)
            coroutineScopeMap[activity] = it
        }
    }

    // 4. UI操作工具
    /**
     * 4.1 获取根视图
     * 
     * @return View? 根视图
     */
    fun getView(): View? = getTopActivity()?.window?.decorView

    /**
     * 4.2 获取内容视图
     * 
     * @return ViewGroup? 内容视图
     */
    fun getContentView(): ViewGroup? = getView()?.findViewById(android.R.id.content) as? ViewGroup

    /**
     * 4.3 打印视图层级
     * 
     * @param v 要打印的视图
     * @param depth 当前深度
     */
    fun dumpView(v: View?, depth: Int) {
        v ?: return
        xLog("${"  ".repeat(depth)}${v.javaClass.name}")
        if (v is ViewGroup) {
            v.children.forEach {
                dumpView(it, depth + 1)
            }
        }
    }

    // 5. Hook初始化
    /**
     * 5.1 初始化Hook环境
     * 设置应用上下文和Activity监听
     * 
     * @param lpparam LoadPackageParam Hook参数
     */
    fun init(lpparam: XC_LoadPackage.LoadPackageParam) {
        // 5.1.1 设置应用上下文
        val instrumentation = XposedHelpers.findClass(
            "android.app.Instrumentation", lpparam.classLoader
        )
        XposedBridge.hookAllMethods(instrumentation, "callApplicationOnCreate", object : XC_MethodHook() {
            @Throws(Throwable::class)
            override fun afterHookedMethod(param: MethodHookParam) {
                app = param.args[0] as Context
            }
        })

        // 5.1.2 监听Activity创建
        val activity = XposedHelpers.findClass(
            "android.app.Activity", lpparam.classLoader
        )
        XposedBridge.hookAllConstructors(activity, object : XC_MethodHook() {
            override fun afterHookedMethod(param: MethodHookParam) {
                if (!getActivities().contains(param.thisObject)) {
                    activityTop.add(0, WeakReference(param.thisObject as Activity))
                }
            }
        })
    }
}

// 6. 日志工具
/**
 * 6.1 Hook实现日志
 * 
 * @param msg 日志消息
 */
fun IHook.xLog(msg: String?) {
    XposedBridge.log("[${this::class.java.simpleName} ${Thread.currentThread().id}] $msg")
}

/**
 * 6.2 普通日志
 * 
 * @param msg 日志消息
 */
fun xLog(msg: String?) {
    XposedBridge.log("[${Thread.currentThread().id}] $msg")
}

/**
 * 6.3 带堆栈的日志
 * 
 * @param param Hook参数
 * @param msg 日志消息
 * @param depth 堆栈深度
 */
fun xLog(param: XC_MethodHook.MethodHookParam?, msg: String?, depth: Int = 15) {
    xLog(msg)
    if (param == null) {
        return
    }
    val stackTrace = Thread.currentThread().stackTrace as Array<StackTraceElement>
    stackTrace.forEachIndexed { index, stackTraceElement ->
        if (stackTraceElement.className.equals("LSPHooker_")) {
            for (i in index + 1..index + depth) {
                if (i < stackTrace.size) {
                    xLog("          ${stackTrace[i].className}.${stackTrace[i].methodName}")
                }
            }
        }
    }
}

/**
 * 6.4 完整堆栈日志
 * 
 * @param param Hook参数
 * @param msg 日志消息
 */
fun xLogTrace(param: XC_MethodHook.MethodHookParam?, msg: String?) {
    if (param == null) {
        xLog(msg)
        return
    }
    xLog(msg)
    val stackTrace = Thread.currentThread().stackTrace as Array<StackTraceElement>
    stackTrace.forEach {
        xLog("          ${it.className}.${it.methodName}")
    }
}

/**
 * 6.5 Toast工具
 * 
 * @param context 上下文
 * @param text 显示文本
 * @param duration 显示时长
 */
fun toast(context: Context?, text: CharSequence, duration: Int) {
    try {
        context?.let {
            Toast.makeText(it, text, duration).show()
        }
    } catch (e: Throwable) {
        xLog("toast: $text")
    }
}

// 7. 协程作用域
/**
 * 7.1 自定义协程作用域
 * 提供异常处理和命名
 */
class MyCoroutineScope: CoroutineScope {
    private val job = Job()
    override val coroutineContext: CoroutineContext = Dispatchers.IO +
            job +
            CoroutineName("MyCoroutineScope") +
            CoroutineExceptionHandler{ coroutineContext, throwable ->
                xLog("coroutineException in $coroutineContext: $throwable")
            }
}